#pragma once

#include <vector>
#include <memory>
#include "llvm/IR/Value.h"

// prog : (expr? ";")*
// expr : term (("+" | "-") term)* ;
// term : factor (("*" | "/") factor)* ;
// factor : number | "(" expr ")" ;
// number: ([0-9])+ ;

enum class OpCode
{
    add,
    sub,
    mul,
    div
};

class Program;
class Expr;
class BinaryExpr;
class FactorExpr;

// 访问者模式
class Visitor
{
public:
    virtual ~Visitor() {}
    virtual llvm::Value *VisitProgram(Program *p) = 0;
    virtual llvm::Value *VisitExpr(Expr *expr) { return nullptr; }
    virtual llvm::Value *VisitBinaryExpr(BinaryExpr *binaryExpr) = 0;
    virtual llvm::Value *VisitFactorExpr(FactorExpr *factorExpr) = 0;
};

class Expr
{
public:
    virtual ~Expr() {}
    virtual llvm::Value *Accept(Visitor *v) { return nullptr; } // 通过虚函数的特性完成分发的功能
};

class BinaryExpr : public Expr
{
public:
    llvm::Value *Accept(Visitor *v) override
    {
        return v->VisitBinaryExpr(this);
    }

public:
    OpCode op;
    std::shared_ptr<Expr> left;
    std::shared_ptr<Expr> right;
};

class FactorExpr : public Expr
{
public:
    llvm::Value *Accept(Visitor *v) override
    {
        return v->VisitFactorExpr(this);
    }

public:
    int number;
};

class Program
{
public:
    std::vector<std::shared_ptr<Expr>> ExprVec;
};
